#import "StefView.h"

// this code is copyright Darcy Brockbank, 1993
//
// You may freely reuse and distribute this code in any way shape or
// form, provided that this notice stays intact.
//
// darcy@hasc.ca, samurai@cs.mcgill.ca
// StefView was implemented out of WorldSpaceView and retains some of the
// movement properties...
//
// The code for WorldSpaceView was written by Sam Streeper at NeXT, I think,
// and there were two other contributors, but I can't find their names in the
// source for it.
//
// StefView is the common "Spotlight" screen saver you see on Macs and Windows
// all the time. This is just a quick hack, and can do with vast amounts of
// improvement I'm sure.
//
// If you do improve this thing, send me a copy!
//
// - darcy

@implementation StefView


#define X_PERIOD 15000.0
#define Y_PERIOD 12000.0
#define DEFAULT_FPS 20
#define PI 3.1415926535
#define MAX_IMAGE_WIDTH 256
#define MAX_IMAGE_HEIGHT 256
#define MAX_X_SPEED (26)
#define MAX_Y_SPEED (26)
#define BUFFER_WIDTH (MAX_IMAGE_WIDTH + MAX_X_SPEED + 1)
#define BUFFER_HEIGHT (MAX_IMAGE_HEIGHT + MAX_Y_SPEED + 1)
#define PRINT(a) printf(a)

#define MINX 0.0
#define MINY 50.0

- takeSpot:(float)x:(float)y;
{
	NXRect r = {{0.0,0.0},{0.0,0.0}};
	NXPoint p = {0.0,0.0};
	[spot lockFocus];
	[spot getSize:&r.size];
	r.origin.x = x;
	r.origin.y = y;
	[clearSpot composite:NX_COPY toPoint:&p];
	[sbuffer composite:NX_DOVER fromRect:&r toPoint:&p];
	[spot unlockFocus];
	return self;
}

- takeSnapshot;
{
	id snapShot;
	NXSize screen;
	static NXRect imageRect = {{0.0,0.0},{0.0,0.0}};
//	NXColor transBlack = NXChangeAlphaComponent(NX_COLORBLACK,0.33);
	[NXApp getScreenSize:&screen];
	imageRect.size = screen;
	snapShot =[[Window alloc] initContent:&imageRect
		style:NX_PLAINSTYLE
		backing:NX_NONRETAINED
		buttonMask:0
		defer:NO];
	PSsetwindowlevel(NX_MAINMENULEVEL+1,[snapShot windowNum]);
	PSsetautofill(NO,[snapShot windowNum]);
	[snapShot orderFront:self];
	NXPing();
	if (!sbuffer) {
		sbuffer = [[NXImage alloc] initSize:&screen];
	}
	[sbuffer lockFocus];
//	NXSetColor(transBlack);
//	NXRectFill(&imageRect);
	PScomposite(0.0,0.0,screen.width,screen.height,[snapShot gState],
		    0.0,0.0,NX_COPY);
	[sbuffer unlockFocus];
	snapShot = [snapShot free];
	return self;
}

- oneStep
{
	NXRect black = {0,0,0,0};
	NXRect ballRect;
	BRECT new;

	then = now;
	now = currentTimeInMs();

	xpos = ((1 + sin(((float)now) / X_PERIOD * 2. * PI))/2.0) 
		* maxCoord.x + MINX;
	ypos = ((1 + sin(((float)now) / Y_PERIOD * 2. * PI))/2.0) 
		* maxCoord.y + MINY;
	
	if (xpos < (old.l - MAX_X_SPEED)) xpos = old.l - MAX_X_SPEED;
	else if (xpos > (old.l + MAX_X_SPEED)) xpos = old.l + MAX_X_SPEED;

	if (ypos < (old.b - MAX_Y_SPEED)) ypos = old.b - MAX_Y_SPEED;
	else if (ypos > (old.b + MAX_Y_SPEED)) ypos = old.b + MAX_Y_SPEED;

	new.l = floor(xpos);
	new.b = floor(ypos);
	new.r = new.l + imageSize.width;
	new.t = new.b + imageSize.height;

	[self takeSpot:new.l :new.b];
	ballRect.origin.x = 0;
	ballRect.origin.y = 0;
	ballRect.size.width = imageSize.width;
	ballRect.size.height = imageSize.height;
	
	redrawTo.x = MIN(new.l, old.l);
	redrawTo.y = MIN(new.b, old.b);

	redraw.origin.x = 0;
	redraw.origin.y = 0;
	redraw.size.width = (MAX(new.r, old.r)) - redrawTo.x + 1;
	redraw.size.height = (MAX(new.t, old.t)) - redrawTo.y + 1;
	
	black.size= redraw.size;

	[buffer lockFocus];
	PSsetgray(0);
	NXRectFill(&black);
	
	ballTo.x = new.l - redrawTo.x;
	ballTo.y = new.b - redrawTo.y;

	[spot composite:NX_SOVER fromRect:&ballRect toPoint:&ballTo];
	[buffer unlockFocus];
	[buffer composite:NX_COPY fromRect:&redraw toPoint:&redrawTo];
	old = new;
	return self;
}


- initFrame:(const NXRect *)frameRect
{
	const char *animSpeed;

	NXRect black = {0, 0, BUFFER_WIDTH, BUFFER_HEIGHT };
	[super initFrame:frameRect];
	[self allocateGState];		// For faster lock/unlockFocus
	[self setClipping:NO];		// even faster...
	//in this case, I only need one buffer for several Views
	if (!(buffer = [NXImage findImageNamed:"worldBuffer"]))
	{
		buffer = [[NXImage alloc] initSize:&black.size];
		[((NXImage *)buffer) setName:"worldBuffer"];
	}
	if ([buffer lockFocus])
	{
		PSsetgray(0);
		NXRectFill(&black);
		[buffer unlockFocus];
	}
	animSpeed = NXGetDefaultValue([NXApp appName], "animSpeed");
	if (animSpeed == NULL) framesPerSecond = DEFAULT_FPS;
	else framesPerSecond = atoi(animSpeed);
	nextRotationTime = 0;
	[self newViewSize];
	return self;
}

- sizeTo:(NXCoord)width :(NXCoord)height
{
	[super sizeTo:width :height];
	[self newViewSize];
	return self;
}

- drawSelf:(const NXRect *)rects :(int)count
{
//	[sbuffer composite:NX_COPY fromRect:rects toPoint:&(rects->origin)];
	return self;
}
	
	
- newViewSize
{
	//this is called every time View size changes
	NXRect black = {0, 0, BUFFER_WIDTH, BUFFER_HEIGHT };

	then = now = currentTimeInMs();

	if (oldSize.width == bounds.size.width &&
			oldSize.height == bounds.size.height)
		return self;
	else
	{
		oldSize.width = bounds.size.width;
		oldSize.height = bounds.size.height;
	}
	
	maxCoord.x = bounds.size.width - imageSize.width - MINX;
	maxCoord.y = bounds.size.height - imageSize.height - MINY;
	if (maxCoord.x < 0) maxCoord.x = 0;
	if (maxCoord.y < 0) maxCoord.y = 0;


	old.l = old.r = maxCoord.x/2 + MINX;
	old.b = old.t = maxCoord.y/2 + MINY;
	ballTo.x = ballTo.y = 0;

	if ([buffer lockFocus])
	{
		PSsetgray(0);
		NXRectFill(&black);
		[buffer unlockFocus];
	}

	return self;
}

- (const char *)windowTitle
{
	return "StefView";
}


- inspector:sender
{
    char buf[MAXPATHLEN];

	if (!sharedInspectorPanel){
		sprintf(buf,"%s/StefView.nib",[sender moduleDirectory:"Stef"]);
		[NXApp loadNibFile:buf owner:self withNames:NO];
		if (!spot) {
			sprintf(buf,"%s/Spot.tiff",[sender moduleDirectory:"Stef"]);
			spot = [[NXImage alloc] initFromFile:buf];
			[spot lockFocus];
			[spot unlockFocus];
			clearSpot = [[NXImage alloc] initFromFile:buf];
			[clearSpot lockFocus];
			[clearSpot unlockFocus];
			[spot getSize:&imageSize];
		}
	}
	[self takeSnapshot];
	return sharedInspectorPanel;
}

@end
